'''
Created on 2012-4-5

@author: qianwp
'''

from popcan.core.structures import Singleton
from Queue import Queue,Empty
from popcan.globals.settings import LogSettings,ServerSettings
import os.path,sys
from datetime import date,datetime
from threading import Timer

class LogLevel:
    DEBUG = 'debug'
    INFO = 'info'
    WARN = 'warn'
    ERROR = 'error'
    FATAL = 'fatal'
    alls = [DEBUG,INFO,WARN,ERROR,FATAL]
    
class Module:
    Middleware = 'middleware'
    Request = 'request'
    Load = 'load'
    Halt = 'halt'
    DB = 'db'
    Mem = 'mem'
    Redis = 'redis'
    Login = 'login'
    Customer = 'customer'
    Designer = 'designer'
    Album = 'album'
    Composit = 'composit'
    Photo = 'photo'
    Comment = 'comment'
    Article = 'article'
    alls = [Middleware,Request,Load,Halt,DB,Mem,Redis,Login,Customer,Designer,Album,Composit,Photo,Comment,Article]

class QueueLogger(Singleton):
    
    def __init__(self):
        self.queues = {}
        self.period = ()
        self.fds = {}
        self.active = False
        if not os.path.exists(LogSettings.logroot):
            os.mkdir(LogSettings.logroot)
        self._ready()
        self._settimer()
        self.active = True
    
    def _ready(self):
        today = date.today()
        self.period = (today.year,today.month,today.day)
        self.flush()
        self._close()
        self.queues.clear()
        self.fds.clear()
        timestr = '%04d%02d%02d' % self.period
        logdir = '%s%s/' % (LogSettings.logroot,timestr)
        if not os.path.exists(logdir):
            os.mkdir(logdir)
        for module in Module.alls:
            self.queues[module] = Queue()
        for level in LogLevel.alls:
            self.fds[level] = open('%sserver%s_%s.txt' % (logdir,ServerSettings.serverId,level),'a')
    
    def _checkcreate(self):
        today = date.today()
        if (today.year,today.month,today.day) != self.period:
            self._ready()
    
    def _settimer(self):
        t = Timer(LogSettings.period,self.dotimer)
        t.start()
        
    def dotimer(self):
        if not self.active:
            return
        self.flush()
        self._settimer()
        
    def log(self,module,msg,level,e=None):
        if self.active:
            queue = self.queues[module]
            queue.put((datetime.now(),level,msg,e))
        if LogSettings.console:
            outer = None
            if level == LogLevel.INFO or level == LogLevel.DEBUG:
                outer = sys.stdout
            else:
                outer = sys.stderr
            outer.write(self._format(module,level,msg,datetime.now()))
            outer.write('\n')
            if e:outer.write(e)
        
    def error(self,module,msg,e=None):
        self.log(module, msg, LogLevel.ERROR,e)
        
    def warn(self,module,msg,e=None):
        self.log(module, msg, LogLevel.WARN,e)
        
    def info(self,module,msg):
        self.log(module, msg, LogLevel.INFO)
        
    def debug(self,module,msg):
        if not LogSettings.debug:return
        self.log(module, msg, LogLevel.DEBUG)
        
    def fatal(self,module,msg):
        self.log(module, msg, LogLevel.FATAL)
        
    def flush(self):
        for module,queue in self.queues.items():
            try:
                while not queue.empty():
                    t,level,msg,e = queue.get_nowait()
                    txt = self._format(module, level, msg, t)
                    lines = (txt,'\n')
                    fd = self.fds[level]
                    fd.writelines(lines)
                    if e:
                        fd.write(e)
            except Empty:
                pass
        self._flush()

    def _flush(self):        
        for fd in self.fds.values():
            fd.flush()
                
    def _close(self):
        for fd in self.fds.values():
            fd.close()
    
    def _format(self,module,level,msg,t):
        timestr = '%04d-%02d-%02d %02d:%02d:%02d' % (t.year,t.month,t.day,t.hour,t.minute,t.second)
        return '%s module=%s level=%s log=%s' % (timestr,module,level,msg)
    
    def shutdown(self):
        self.flush()
        self._close()
        self.queues.clear()
        self.active = False